﻿package fr.babos.core.data.remote 
{
	/**
	 * Les imports
	 */
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import fr.babos.core.data.parse.DataParser;
	import fr.babos.core.data.parse.IDataParser;
	import fr.babos.core.data.remote.IDataRemote;
	import fr.babos.core.roles.IDisposable;
	import fr.babos.core.utils.ArrayUtils;
	
	/**
	 * La remote abstraite.
	 * Ne pas instancier directement cette classe, seules ses classes filles peuvent être instanciées.
	 * @author ZoulouX
	 */
	public class ADataRemote extends EventDispatcher implements IEventDispatcher, IDataRemote, IDisposable
	{
		/**
		 * Le parser
		 */
		protected var _parser					:IDataParser			= new DataParser();
		
		/**
		 * Parser automatiquement
		 */
		protected var _autoParse				:Boolean				= true;
		
		/**
		 * La liste des calls
		 */
		protected var _calls					:Array					= [];
		
		/**
		 * L'id de call courrant
		 */
		protected var _callId					:uint					= 0;
		
		/**
		 * Vider les calls terminés automatiquement
		 */
		protected var _autoGarbageCalls			:Boolean 				= true;
		
		/**
		 * Activer le mode queue.
		 * Ce mode permet d'éviter qu'il y ai plusieurs appels en cours sur une même remote.
		 * Si un appel B est effectué alors qu'un appel A est en cours, l'appel B sera exécuté qu'une fois l'appel A terminé (success ou error)
		 */
		protected var _queueMode				:Boolean 				= true;
		
		
		/**
		 * Le parser
		 */
		public function get parser ():IDataParser { return _parser; }
		public function set parser (value:IDataParser):void 
		{
			// Vérifier que le parser ne soit pas null
			if (value != null)
				_parser = value;
			else
				throw new Error("ADataRemote.parser Error. Can't associate null parser.");
		}
		
		/**
		 * Parser automatiquement
		 */
		public function get autoParse ():Boolean { return _autoParse; }
		public function set autoParse (value:Boolean):void 
		{
			_autoParse = value;
		}
		
		/**
		 * Récupérer la liste des appels
		 */
		public function get calls ():Array { return _calls; }
		
		/**
		 * Récupérer le nombre de calls en cours d'exécution
		 */
		public function get totalCalls ():uint { return _calls.length;  }
		
		/**
		 * Récupérer le dernier id d'appel
		 */
		public function get callId ():uint { return _callId; }
		
		/**
		 * Récupérer le dernier appel
		 */
		public function get lastCall ():RemotingCall
		{
			return _calls[_calls.length - 1] as RemotingCall;
		}
		
		/**
		 * Vider les calls terminés automatiquement, directement après les envois d'event
		 */
		public function get autoGarbageCalls ():Boolean { return _autoGarbageCalls; }
		public function set autoGarbageCalls (value:Boolean):void 
		{
			_autoGarbageCalls = value;
		}
		
		/**
		 * Activer le mode queue.
		 * Ce mode permet d'éviter qu'il y ai plusieurs appels en cours sur une même remote.
		 * Si un appel B est effectué alors qu'un appel A est en cours, l'appel A sera exécuté qu'une fois l'appel B terminé (success ou error)
		 */
		public function get queueMode ():Boolean { return _queueMode; }
		public function set queueMode (value:Boolean):void 
		{
			_queueMode = value;
		}
		
		/**
		 * Le constructeur de la remote
		 */
		public function ADataRemote ()
		{
			
		}
		
		/**
		 * La méthode call, à concrêtiser en overridant.
		 * @param pCommand : Le nom de la commande à exécuter
		 * @param pOptions : Les options de l'appel
		 * @param ... rest : Les paramètres non nommés optionnels.
		 * @return : L'objet call contenant son id et sa commande.
		 */
		public function call (pCommand:String, pOptions:Object = null, ... rest):RemotingCall
		{
			// Par défaut, déclancher une erreur
			throw new Error("ADataRemote.call Error. This is an abstract method which you must override.");
			return null;
		}
		
		/**
		 * Vider la liste des call qui sont terminés
		 */
		public function garbageCalls ():void
		{
			// Parcourir tous les calls
			var total:uint = _calls.length;
			for (var i:int = 0; i < total; i++) 
			{
				// Récupérer les éléments terminés
				if ((_calls[i] as RemotingCall).complete)
				{
					// Tuer les références de cet appel
					(_calls[i] as IDisposable).dispose();
					
					// Le supprimer du tableau
					_calls = ArrayUtils.deleteIndex(_calls, i);
				}
			}
		}
		
		/**
		 * Arrêter tous les appels
		 */
		public function cancelQueue ():void
		{
			// Parcourir tous les calls
			var total:uint = _calls.length;
			for (var i:int = 0; i < total; i++) 
			{
				// Tuer les références de cet appel
				(_calls[i] as IDisposable).dispose();
			}
			
			// Vider le tableau
			_calls = [];
		}
		
		/**
		 * Effectuer l'appel suivant
		 */
		public function callNext ():void
		{
			//(_calls[i] as RemotingCall).execute();
		}
		
		/**
		 * Effacer cet objet.
		 * Methode à concrêtiser sinon on te pète les doigts.
		 */
		public function dispose ():void
		{
			// Vider la queue
			cancelQueue();
		}
	}
}